}
static void
-_dvb_sub_parse_page_segment (DvbSub * dvb_sub, guint16 page_id, guint8 * buf,
- gint buf_size)
+_dvb_sub_parse_page_segment (DvbSub * dvb_sub, guint16 page_id,
+ const guint8 * buf, gint buf_size)
{ /* FIXME: Use guint for buf_size here and in many other places? */
DVBSubRegionDisplay *display;
DVBSubRegionDisplay *tmp_display_list, **tmp_ptr;
}
static void
-_dvb_sub_parse_region_segment (DvbSub * dvb_sub, guint16 page_id, guint8 * buf,
- gint buf_size)
+_dvb_sub_parse_region_segment (DvbSub * dvb_sub, guint16 page_id,
+ const guint8 * buf, gint buf_size)
{
const guint8 *buf_end = buf + buf_size;
guint8 region_id;
region->height = GST_READ_UINT16_BE (buf);
buf += 2;
+ /* Avoid integer overflows and also clamp to a reasonable size of 8kx8k for
+ * the region size. We allow 16kx16k display sizes. */
+ if (region->width > 8192 || region->height > 8192) {
+ GST_WARNING ("too large region of %ux%x", region->width, region->height);
+ g_free (region->pbuf);
+ region->pbuf = NULL;
+ region->buf_size = 0;
+ region->width = region->height = 0;
+ return;
+ }
+
if (region->width * region->height != region->buf_size) { /* FIXME: Read closer from spec what happens when dimensions change */
g_free (region->pbuf);
}
static void
-_dvb_sub_parse_clut_segment (DvbSub * dvb_sub, guint16 page_id, guint8 * buf,
- gint buf_size)
+_dvb_sub_parse_clut_segment (DvbSub * dvb_sub, guint16 page_id,
+ const guint8 * buf, gint buf_size)
{
const guint8 *buf_end = buf + buf_size;
guint8 clut_id;
GST_MEMDUMP ("DVB clut packet", buf, buf_size);
+ if (buf_size < 1)
+ return;
+
clut_id = *buf++;
buf += 1;
dvb_sub->clut_list = clut;
}
- while (buf + 4 < buf_end) {
+ while (buf + 2 < buf_end) {
entry_id = *buf++;
depth = (*buf) & 0xe0;
full_range = (*buf++) & 1;
if (full_range) {
+ if (buf + 4 > buf_end)
+ break;
y = *buf++;
cr = *buf++;
cb = *buf++;
alpha = *buf++;
} else {
+ if (buf + 2 > buf_end)
+ break;
y = buf[0] & 0xfc;
cr = (((buf[0] & 3) << 2) | ((buf[1] >> 6) & 3)) << 4;
cb = (buf[1] << 2) & 0xf0;
GST_DEBUG ("CLUT DEFINITION: clut %d := (%d,%d,%d,%d)", entry_id, y, cb, cr,
alpha);
- if (depth & 0x80)
+ if ((depth & 0x80) && entry_id < 4)
clut->clut4[entry_id] = AYUV (y, cb, cr, 255 - alpha);
- if (depth & 0x40)
+ if ((depth & 0x40) && entry_id < 16)
clut->clut16[entry_id] = AYUV (y, cb, cr, 255 - alpha);
- if (depth & 0x20)
+ if ((depth & 0x20) && entry_id < 256)
clut->clut256[entry_id] = AYUV (y, cb, cr, 255 - alpha);
}
}
const guint8 ** srcbuf, gint buf_size, guint8 non_mod, guint8 * map_table)
{
GstBitReader gb = GST_BIT_READER_INIT (*srcbuf, buf_size);
- /* FIXME: Handle FALSE returns from gst_bit_reader_get_* calls? */
-
gboolean stop_parsing = FALSE;
guint32 bits = 0;
guint32 pixels_read = 0;
while (!stop_parsing && (gst_bit_reader_get_remaining (&gb) > 1)) {
guint run_length = 0, clut_index = 0;
- bits = gst_bit_reader_get_bits_uint32_unchecked (&gb, 2);
+ if (!gst_bit_reader_get_bits_uint32 (&gb, &bits, 2))
+ goto not_enough_data;
if (bits) { /* 2-bit_pixel-code */
run_length = 1;
clut_index = bits;
} else { /* 2-bit_zero */
- bits = gst_bit_reader_get_bits_uint32_unchecked (&gb, 1);
+ if (!gst_bit_reader_get_bits_uint32 (&gb, &bits, 1))
+ goto not_enough_data;
if (bits == 1) { /* switch_1 == '1' */
- run_length = gst_bit_reader_get_bits_uint32_unchecked (&gb, 3);
+ if (!gst_bit_reader_get_bits_uint32 (&gb, &run_length, 3))
+ goto not_enough_data;
run_length += 3;
- clut_index = gst_bit_reader_get_bits_uint32_unchecked (&gb, 2);
+ if (!gst_bit_reader_get_bits_uint32 (&gb, &clut_index, 2))
+ goto not_enough_data;
} else { /* switch_1 == '0' */
- bits = gst_bit_reader_get_bits_uint32_unchecked (&gb, 1);
+ if (!gst_bit_reader_get_bits_uint32 (&gb, &bits, 1))
+ goto not_enough_data;
if (bits == 1) { /* switch_2 == '1' */
run_length = 1; /* 1x pseudo-colour '00' */
} else { /* switch_2 == '0' */
- bits = gst_bit_reader_get_bits_uint32_unchecked (&gb, 2);
+ if (!gst_bit_reader_get_bits_uint32 (&gb, &bits, 2))
+ goto not_enough_data;
switch (bits) { /* switch_3 */
case 0x0: /* end of 2-bit/pixel_code_string */
stop_parsing = TRUE;
run_length = 2;
break;
case 0x2: /* the following 6 bits contain run length coded pixel data */
- run_length = gst_bit_reader_get_bits_uint32_unchecked (&gb, 4);
+ if (!gst_bit_reader_get_bits_uint32 (&gb, &run_length, 4))
+ goto not_enough_data;
run_length += 12;
- clut_index = gst_bit_reader_get_bits_uint32_unchecked (&gb, 2);
+ if (!gst_bit_reader_get_bits_uint32 (&gb, &clut_index, 2))
+ goto not_enough_data;
break;
case 0x3: /* the following 10 bits contain run length coded pixel data */
- run_length = gst_bit_reader_get_bits_uint32_unchecked (&gb, 8);
+ if (!gst_bit_reader_get_bits_uint32 (&gb, &run_length, 8))
+ goto not_enough_data;
run_length += 29;
- clut_index = gst_bit_reader_get_bits_uint32_unchecked (&gb, 2);
+ if (!gst_bit_reader_get_bits_uint32 (&gb, &clut_index, 2))
+ goto not_enough_data;
break;
}
}
pixels_read += run_length;
}
- // FIXME: Test skip_to_byte instead of adding 7 bits, once everything else is working good
- //gst_bit_reader_skip_to_byte (&gb);
- *srcbuf += (gst_bit_reader_get_pos (&gb) + 7) >> 3;
+ gst_bit_reader_skip_to_byte (&gb);
+ *srcbuf = gb.data + gb.byte;
GST_TRACE ("PIXEL: returning, read %u pixels", pixels_read);
// FIXME: Shouldn't need this variable if tracking things in the loop better
return pixels_read;
+
+not_enough_data:
+ GST_WARNING ("Not enough data");
+ // Go to the end of the buffer so the caller stops parsing
+ *srcbuf += buf_size;
+ return 0;
}
// FFMPEG-FIXME: The same code in ffmpeg is much more complex, it could use the same
const guint8 ** srcbuf, gint buf_size, guint8 non_mod, guint8 * map_table)
{
GstBitReader gb = GST_BIT_READER_INIT (*srcbuf, buf_size);
- /* FIXME: Handle FALSE returns from gst_bit_reader_get_* calls? */
gboolean stop_parsing = FALSE;
guint32 bits = 0;
guint32 pixels_read = 0;
while (!stop_parsing && (gst_bit_reader_get_remaining (&gb) > 3)) {
guint run_length = 0, clut_index = 0;
- bits = gst_bit_reader_get_bits_uint32_unchecked (&gb, 4);
+ if (!gst_bit_reader_get_bits_uint32 (&gb, &bits, 4))
+ goto not_enough_data;
if (bits) {
run_length = 1;
clut_index = bits;
} else {
- bits = gst_bit_reader_get_bits_uint32_unchecked (&gb, 1);
+ if (!gst_bit_reader_get_bits_uint32 (&gb, &bits, 1))
+ goto not_enough_data;
if (bits == 0) { /* switch_1 == '0' */
- run_length = gst_bit_reader_get_bits_uint32_unchecked (&gb, 3);
+ if (!gst_bit_reader_get_bits_uint32 (&gb, &run_length, 3))
+ goto not_enough_data;
if (!run_length) {
stop_parsing = TRUE;
} else {
run_length += 2;
}
} else { /* switch_1 == '1' */
- bits = gst_bit_reader_get_bits_uint32_unchecked (&gb, 1);
+ if (!gst_bit_reader_get_bits_uint32 (&gb, &bits, 1))
+ goto not_enough_data;
if (bits == 0) { /* switch_2 == '0' */
- run_length = gst_bit_reader_get_bits_uint32_unchecked (&gb, 2);
+ if (!gst_bit_reader_get_bits_uint32 (&gb, &run_length, 2))
+ goto not_enough_data;
run_length += 4;
- clut_index = gst_bit_reader_get_bits_uint32_unchecked (&gb, 4);
+ if (!gst_bit_reader_get_bits_uint32 (&gb, &clut_index, 4))
+ goto not_enough_data;
} else { /* switch_2 == '1' */
- bits = gst_bit_reader_get_bits_uint32_unchecked (&gb, 2);
+ if (!gst_bit_reader_get_bits_uint32 (&gb, &bits, 2))
+ goto not_enough_data;
switch (bits) {
case 0x0: /* switch_3 == '00' */
run_length = 1; /* 1 pixel of pseudo-color 0 */
run_length = 2; /* 2 pixels of pseudo-color 0 */
break;
case 0x2: /* switch_3 == '10' */
- run_length = gst_bit_reader_get_bits_uint32_unchecked (&gb, 4);
+ if (!gst_bit_reader_get_bits_uint32 (&gb, &run_length, 4))
+ goto not_enough_data;
run_length += 9;
- clut_index = gst_bit_reader_get_bits_uint32_unchecked (&gb, 4);
+ if (!gst_bit_reader_get_bits_uint32 (&gb, &clut_index, 4))
+ goto not_enough_data;
break;
case 0x3: /* switch_3 == '11' */
- run_length = gst_bit_reader_get_bits_uint32_unchecked (&gb, 8);
+ if (!gst_bit_reader_get_bits_uint32 (&gb, &run_length, 8))
+ goto not_enough_data;
run_length += 25;
- clut_index = gst_bit_reader_get_bits_uint32_unchecked (&gb, 4);
+ if (!gst_bit_reader_get_bits_uint32 (&gb, &clut_index, 4))
+ goto not_enough_data;
break;
}
}
pixels_read += run_length;
}
- // FIXME: Test skip_to_byte instead of adding 7 bits, once everything else is working good
- //gst_bit_reader_skip_to_byte (&gb);
- *srcbuf += (gst_bit_reader_get_pos (&gb) + 7) >> 3;
+ gst_bit_reader_skip_to_byte (&gb);
+ *srcbuf = gb.data + gb.byte;
GST_LOG ("Returning with %u pixels read", pixels_read);
// FIXME: Shouldn't need this variable if tracking things in the loop better
return pixels_read;
+
+not_enough_data:
+ GST_WARNING ("Not enough data");
+ // Go to the end of the buffer so the caller stops parsing
+ *srcbuf += buf_size;
+ return 0;
}
static int
const guint8 ** srcbuf, gint buf_size, guint8 non_mod, guint8 * map_table)
{
GstBitReader gb = GST_BIT_READER_INIT (*srcbuf, buf_size);
- /* FIXME: Handle FALSE returns from gst_bit_reader_get_* calls? */
-
gboolean stop_parsing = FALSE;
guint32 bits = 0;
guint32 pixels_read = 0;
/* Rephrased - it's better to work with bytes with default value '0' instead of reading from memory we don't own. */
while (!stop_parsing && (gst_bit_reader_get_remaining (&gb) > 7)) {
guint run_length = 0, clut_index = 0;
- bits = gst_bit_reader_get_bits_uint32_unchecked (&gb, 8);
+
+ if (!gst_bit_reader_get_bits_uint32 (&gb, &bits, 8))
+ goto not_enough_data;
if (bits) { /* 8-bit_pixel-code */
run_length = 1;
clut_index = bits;
} else { /* 8-bit_zero */
- bits = gst_bit_reader_get_bits_uint32_unchecked (&gb, 1);
+ if (!gst_bit_reader_get_bits_uint32 (&gb, &bits, 1))
+ goto not_enough_data;
if (bits == 0) { /* switch_1 == '0' */
/* run_length_1-127 for pseudo-colour _entry) '0x00' */
- run_length = gst_bit_reader_get_bits_uint32_unchecked (&gb, 7);
+ if (!gst_bit_reader_get_bits_uint32 (&gb, &run_length, 7))
+ goto not_enough_data;
if (run_length == 0) { /* end_of_string_signal */
stop_parsing = TRUE;
}
} else { /* switch_1 == '1' */
/* run_length_3-127 */
- run_length = gst_bit_reader_get_bits_uint32_unchecked (&gb, 7);
- clut_index = gst_bit_reader_get_bits_uint32_unchecked (&gb, 8);
+ if (!gst_bit_reader_get_bits_uint32 (&gb, &run_length, 7))
+ goto not_enough_data;
+ if (!gst_bit_reader_get_bits_uint32 (&gb, &clut_index, 8))
+ goto not_enough_data;
if (run_length < 3) {
GST_WARNING ("runlength value was %u, but the spec requires it "
GST_LOG ("Returning with %u pixels read", pixels_read);
- *srcbuf += (gst_bit_reader_get_pos (&gb) + 7) >> 3;
+ gst_bit_reader_skip_to_byte (&gb);
+ *srcbuf = gb.data + gb.byte;
// FIXME: Shouldn't need this variable if tracking things in the loop better
return pixels_read;
+
+not_enough_data:
+ GST_WARNING ("Not enough data");
+ // Go to the end of the buffer so the caller stops parsing
+ *srcbuf += buf_size;
+ return 0;
}
static void
guint8 *pbuf;
int x_pos, y_pos;
int i;
- gboolean dest_buf_filled = FALSE;
guint8 map2to4[] = { 0x0, 0x7, 0x8, 0xf };
guint8 map2to8[] = { 0x00, 0x77, 0x88, 0xff };
// FFMPEG-FIXME: ffmpeg doesn't check for equality and so can overflow destination buffer later on with bad input data
// FFMPEG-FIXME: However that makes it warn on end_of_object_line and map tables as well, so we add the dest_buf_filled tracking
- // FIXME: Removed x_pos checking here, because we don't want to turn dest_buf_filled to TRUE permanently in that case
- // FIXME: We assume that region->width - x_pos as dbuf_len to read_nbit_string will take care of that case nicely;
- // FIXME: That is, that read_nbit_string never scribbles anything if dbuf_len passed to it is zero due to this.
- if (y_pos >= region->height) {
- dest_buf_filled = TRUE;
+ if (x_pos >= region->width || y_pos >= region->height) {
+ GST_WARNING ("Invalid object location for data_type 0x%x!", *buf);
+ return;
}
switch (*buf++) {
case 0x10:
- if (dest_buf_filled) {
- /* FIXME: Be more verbose */
- GST_WARNING ("Invalid object location for data_type 0x%x!",
- *(buf - 1));
- GST_MEMDUMP ("Remaining data after invalid object location:", buf,
- (guint) (buf_end - buf));
- return;
- }
-
if (region->depth == 8)
map_table = map2to8;
else if (region->depth == 4)
region->width - x_pos, &buf, buf_end - buf, non_mod, map_table);
break;
case 0x11:
- if (dest_buf_filled) {
- /* FIXME: Be more verbose */
- GST_WARNING ("Invalid object location for data_type 0x%x!",
- *(buf - 1));
- GST_MEMDUMP ("Remaining data after invalid object location:", buf,
- buf_end - buf);
- return; // FIXME: Perhaps tell read_nbit_string that dbuf_len is zero and let it walk the bytes regardless? (Same FIXME for 2bit and 8bit)
- }
-
if (region->depth < 4) {
GST_WARNING ("4-bit pixel string in %d-bit region!", region->depth);
return;
GST_DEBUG ("READ_4BIT_STRING finished: buf pointer now %p", buf);
break;
case 0x12:
- if (dest_buf_filled) {
- /* FIXME: Be more verbose */
- GST_WARNING ("Invalid object location for data_type 0x%x!",
- *(buf - 1));
- GST_MEMDUMP ("Remaining data after invalid object location:",
- buf, (guint) (buf_end - buf));
- return;
- }
-
if (region->depth < 8) {
GST_WARNING ("8-bit pixel string in %d-bit region!", region->depth);
return;
case 0x20:
GST_DEBUG ("handling map2to4 table data");
- /* FIXME: I don't see any guards about buffer size here - buf++ happens with the switch, but
- * FIXME: buffer is walked without length checks? Same deal in other map table cases */
+ if (buf + 2 > buf_end) {
+ GST_WARNING ("map2to4 table too short");
+ return;
+ }
map2to4[0] = (*buf) >> 4;
map2to4[1] = (*buf++) & 0xf;
map2to4[2] = (*buf) >> 4;
map2to4[3] = (*buf++) & 0xf;
break;
case 0x21:
+ if (buf + 4 > buf_end) {
+ GST_WARNING ("map2to8 table too short");
+ return;
+ }
GST_DEBUG ("handling map2to8 table data");
for (i = 0; i < 4; i++)
map2to8[i] = *buf++;
break;
case 0x22:
+ if (buf + 16 > buf_end) {
+ GST_WARNING ("map4to8 table too short");
+ return;
+ }
GST_DEBUG ("handling map4to8 table data");
for (i = 0; i < 16; i++)
map4to8[i] = *buf++;
}
static void
-_dvb_sub_parse_object_segment (DvbSub * dvb_sub, guint16 page_id, guint8 * buf,
- gint buf_size)
+_dvb_sub_parse_object_segment (DvbSub * dvb_sub, guint16 page_id,
+ const guint8 * buf, gint buf_size)
{
const guint8 *buf_end = buf + buf_size;
guint object_id;
guint8 coding_method, non_modifying_color;
+ if (buf_size < 3)
+ return;
+
object_id = GST_READ_UINT16_BE (buf);
buf += 2;
DVBSubObjectDisplay *display;
guint16 top_field_len, bottom_field_len;
+ if (buf + 4 > buf_end)
+ return;
+
top_field_len = GST_READ_UINT16_BE (buf);
buf += 2;
bottom_field_len = GST_READ_UINT16_BE (buf);
}
static gint
-_dvb_sub_parse_display_definition_segment (DvbSub * dvb_sub, guint8 * buf,
+_dvb_sub_parse_display_definition_segment (DvbSub * dvb_sub, const guint8 * buf,
gint buf_size)
{
int dds_version, info_byte;
display_height = GST_READ_UINT16_BE (buf) + 1;
buf += 2;
+ /* Avoid integer overflows and also clamp to a reasonable size of 16kx16k */
+ if (display_width > 16384 || display_height > 16384) {
+ GST_WARNING ("too large display size of %ux%x", display_width,
+ display_height);
+ /* Reset to the initial values */
+ dvb_sub->display_def.version = -1;
+ dvb_sub->display_def.window_flag = 0;
+ dvb_sub->display_def.display_width = 720;
+ dvb_sub->display_def.display_height = 576;
+ return -1;
+ }
+
if ((display_width != dvb_sub->display_def.display_width)
|| (display_height != dvb_sub->display_def.display_height)) {
dvb_sub->display_def.display_width = display_width;
* 0 or positive if data was handled. If positive, then amount of data consumed on success. FIXME: List the positive return values.
*/
gint
-dvb_sub_feed_with_pts (DvbSub * dvb_sub, guint64 pts, guint8 * data, gint len)
+dvb_sub_feed_with_pts (DvbSub * dvb_sub, guint64 pts, const guint8 * data,
+ gint len)
{
unsigned int pos = 0;
guint8 segment_type;